/*   The MIT License
 *   
 *   Carina Engine
 *   Copyright (c) 2009 2010 2011 2012 Zdravko Velinov
 *   
 *   Permission is hereby granted, free of charge, to any person obtaining a copy
 *   of this software and associated documentation files (the "Software"), to deal
 *   in the Software without restriction, including without limitation the rights
 *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *   copies of the Software, and to permit persons to whom the Software is
 *   furnished to do so, subject to the following conditions:
 *
 *   The above copyright notice and this permission notice shall be included in
 *   all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *   THE SOFTWARE.
 */

#ifndef CARINA_WINDOW_WIN32_HH
#define CARINA_WINDOW_WIN32_HH

#include <X11/Xlib.h>

#include <GL/gl.h>
#include <GL/glx.h>
#include "GL/glxext.h"

#include "carina/window.hh"

#include "carina/renderer-base.hh"

namespace Carina
{
extern const int event_mask;

typedef ::Window    WindowId;
typedef ::Display*  DisplayId;

class WindowInfo
{
    WindowId    m_Window;
    DisplayId   m_Display;
public:
    WindowInfo()
        :   m_Window(0),
            m_Display(0) {}

    WindowInfo(WindowId wid, DisplayId did)
        :   m_Window(wid),
            m_Display(did) {}
    
    inline DisplayId getDisplayId() const { return m_Display; }
    inline void setDisplayId(DisplayId did) { m_Display = did; }

    inline WindowId getWindowId() const { return m_Window; }
    inline void setWindowId(WindowId wid) { m_Window = wid; }
};

class WindowManager;

class WindowImpl
{
protected:
    WindowId        m_Window;
    DisplayId       m_Display;
public:
    WindowImpl();
    virtual ~WindowImpl();

    virtual void swapBuffers()=0;
    virtual RendererPtr getRenderer()=0;

    WindowInfo getInfo() const { return WindowInfo(m_Window, m_Display); }
    WindowId getWindowId() const { return m_Window; }
    DisplayId getDisplayId() const { return m_Display; }

    size_t getWidth() const;
    size_t getHeight() const;

    void _destroyX11();

    void setTitle(const string& name);
    void show();

    virtual void destroy()=0;
    virtual void resize(size_t w, size_t h)=0;
    virtual void create(WindowManager& win, size_t w, size_t h, size_t samples, const WindowInfo& parent=WindowInfo())=0;
};

typedef shared_ptr<WindowImpl> WindowImplPtr;

class Window
{
    WindowImplPtr   m_WImpl;
    size_t          m_MSAA;
    int             m_CurCursorX,
                    m_CurCursorY;
public:
    Window(WindowManager& wmgr, const WindowImplPtr& wimpl, const WindowDescription& desc);
     ~Window();

    WindowInfo getInfo() const { return m_WImpl->getInfo(); }

    size_t getWidth() const { return m_WImpl->getWidth(); }
    size_t getHeight() const { return m_WImpl->getHeight(); }

    size_t getMSAA() const { return m_MSAA; }
    
    inline RendererPtr getRenderer() { return m_WImpl->getRenderer(); }
    void swapBuffers();
private:
    static KeyboardKey getKey(KeySym key);

EVENTS_LIST:
    DECLARE_EVENT(KeyboardEvent)
    DECLARE_EVENT(ResizeWindowEvent)
    DECLARE_EVENT(MouseMotionEvent)
    DECLARE_EVENT(QuitEvent)
};

class WindowManager
{
    DisplayId       m_Display;
public:
    WindowManager(const string& _icon);
    ~WindowManager();

    DisplayId getDisplay() const { return m_Display; }

    WindowPtr createWindow(const RenderingLibraryPtr& lib, const WindowDescription& desc);
};

typedef shared_ptr<WindowManager> WindowManagerPtr;
}
#endif
